#define _POSIX_SOURCE
#define _BSD_SOURCE

#include "dominion.h"
#include "dominion_helpers.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include "rngs.h"
#include <getopt.h>

#ifndef TEST_CASES
#define TEST_CASES 10000
#endif

#ifndef RAND_NUM
#define RAND_NUM 100
#endif

#ifndef SUPP
#define SUPP 10
#endif

int createGameState(struct gameState *state, int card, int *handPos)
{
	int i, j, treasure_card = 0;

	// Generate 2-4 players
	state->numPlayers = floor(Random() * (MAX_PLAYERS - 1)) + 2;
	state->whoseTurn = floor(Random() * state->numPlayers);

	state->numActions = floor(Random() * RAND_NUM);
	state->numBuys = floor(Random() * RAND_NUM);
	state->coins = floor(Random() * RAND_NUM);
	state->playedCardCount = floor(Random() * RAND_NUM);

	// Generate Supply Cards
	for (i = 0; i <= treasure_map; i++) {
		state->supplyCount[i] = floor(Random() * SUPP);
	}

	for (i = 0; i < state->numPlayers; i++) {
		state->handCount[i] = floor(Random() * RAND_NUM);
		state->deckCount[i] = floor(Random() * (RAND_NUM - 4)) + 5;
		state->discardCount[i] = floor(Random() * RAND_NUM);

		for (j = 0; j < state->handCount[i]; j++) {
			state->hand[i][j] = floor(Random() * (treasure_map + 1));
		}

		for (j = 0; j < state->deckCount[i]; j++) {
			state->deck[i][j] = floor(Random() * (treasure_map + 1));
		}

		for (j = 0; j < state->discardCount[i]; j++) {
			state->discard[i][j] = floor(Random() * (treasure_map + 1));
		}
	}

	// Make sure current player has the card to test
	if (state->handCount[state->whoseTurn] <= 0) {
		state->hand[state->whoseTurn][0] = card;
		state->handCount[state->whoseTurn] += 1;
		*handPos = 0;
	} else {
		*handPos = floor(Random() * state->handCount[state->whoseTurn]);
		state->hand[state->whoseTurn][*handPos] = card;

		// Give 80% chance to generate another treasure card
		if (((int) floor(Random() * 100) + 1) > 20) {
			do {
				treasure_card = floor(Random() * state->handCount[state->whoseTurn]);
			} while ((treasure_card == *handPos) && (state->handCount[state->whoseTurn] > 1));
			state->hand[state->whoseTurn][treasure_card] = treasure_map;
		}
	}

	return 0;
}

int test_cardtreasuremap(struct gameState *state, int handPos)
{
	int i, j, status = 0, treasure_count = 0, gain_gold = 4;
	struct gameState pre;

	memcpy(&pre, state, sizeof(struct gameState));

	cardEffect(treasure_map, -1, -1, -1, state, handPos, NULL);

	// Count number of treasure cards
	for (i = 0; i < pre.handCount[pre.whoseTurn]; i++) {
		if (pre.hand[pre.whoseTurn][i] == treasure_map) {
			treasure_count += 1;
		}
	}

	if (treasure_count >= 2) {
		// Trash 2 treasure cards
		for (i = 0; i < 2; i++) {
			for (j = 0; j < pre.handCount[pre.whoseTurn]; j++) {
				if (pre.hand[pre.whoseTurn][i] == treasure_map) {
					discardCard(i, pre.whoseTurn, &pre, 1);	// Trash card
					break;
				}
			}
		}

		// Put 4 gold cards on top of current player's deckf if possible
		if (gain_gold > pre.supplyCount[gold]) {
			gain_gold = pre.supplyCount[gold];
		}

		for (i = 0; i < gain_gold; i++) {
			pre.deck[pre.whoseTurn][pre.deckCount[pre.whoseTurn]] = gold;
			pre.deckCount[pre.whoseTurn] += 1;
		}

		pre.supplyCount[gold] -= gain_gold;
	} else {
      discardCard(handPos, pre.whoseTurn, &pre, 1);
    }

	if (memcmp(&pre, state, sizeof(struct gameState)) != 0) {
		status = -1;
	}

	return status;
}

int main(int argc, char **argv)
{
	int i, result, handPos, counter = 0;
	struct gameState state;

	for (i = 0; i < TEST_CASES; i++) {

		// Reset variables
		handPos = 0;
		
		createGameState(&state, treasure_map, &handPos);
		result = test_cardtreasuremap(&state, handPos);
		if (result == 0) {
			printf("TEST CASE #%d = PASS\n", i + 1);
			counter += 1;
		} else if (result == 1) { // Case that cannot be tested
			i--;
			continue;
		} else {
			printf("TEST CASE #%d = FAIL <------\n", i + 1);
			//outputState(&state, stderr);
		}
	}

	printf("PASSED CASES: %d out of %d\n", counter, TEST_CASES);
	return 0;
}